#include "Individuo.hpp"


#define     DXF_LATO_CFB    14
#define     DXF_V_GAP       6
#define     DXF_O_GAP       6

#ifdef USE_STD_CONFIG
	#define STD_CONFIG_NUM	4
	Std_Config configArray[] = {
		{"MUXA1", 0x55555555},
		{"MUXA2", 0x33333333},
		{"MUXA3", 0x0F0F0F0F},
		{"MUXA4", 0x00FF00FF},
		{"AND12", 0x11111111},
		{"AND13", 0x05050505},
		{"AND14", 0x00550055},
		{"AND23", 0x03030303},
		{"AND24", 0x00330033},
		{"AND34", 0x000F000F},
		{"OR12" , 0x77777777},
		{"OR13" , 0x5F5F5F5F},
		{"OR14" , 0x55FF55FF},
		{"OR23" , 0x3F3F3F3F},
		{"OR24" , 0x33FF33FF},
		{"OR34" , 0x0FFF0FFF},
		{"SUMB3", 0xEC80EC80},
		{"SUMB2", 0x936C936C},
		{"SUMB1", 0x5A5A5A5A},
		};
#endif


#ifdef INJECT_ERRORS
	#define ERROR_LIST_DIM	8
	Malfunction malfArray[] = {
		{0, 2, 0xFFFFFFFF},
		{0, 3, 0xFFFFFFFF},
		{1, 1, 0xFFFFFFFF},
		{1, 5, 0xFFFFFFFF},
		{1, 6, 0xFFFFFFFF},
		{2, 2, 0xFFFFFFFF},
		{0, 6, 0xFFFFFFFF},
		{2, 1, 0xFFFFFFFF},
		{0, 4, 0xFFFFFFFF},
		{2, 2, 0xFFFFFFFF},
		{1, 4, 0xFFFFFFFF},
		{2, 7, 0xFFFFFFFF},

		{0, 6, 0xFFFFFFFF},
		{3, 7, 0xFFFFFFFF},
		{3, 4, 0xFFFFFFFF},
		{0, 1, 0xFFFFFFFF},
		{0, 2, 0xFFFFFFFF},
		{1, 1, 0xFFFFFFFF},

	};
#endif

Individuo::Individuo(int rows, int cols)
{
	int i;


	if (cols==-1 || rows == -1)
	{
		COLS = DEF_COLS;
		ROWS = DEF_ROWS;
	}
	else
	{
		COLS = cols;
		ROWS = rows;
	}

	CellGrid = (Cell**)malloc(COLS*sizeof(Cell*));
	for(i=0; i<COLS; i++)
	{
		CellGrid[i] = (Cell*)malloc(ROWS*sizeof(Cell));
	}
    fitness  = 0;
    mod      = 1;

}

Individuo::~Individuo()
{
	int i;
	for(i=0; i<COLS; i++)
		free(CellGrid[i]);
	free(CellGrid);

}


void Individuo::randomInit()
{
    int i,j,p;
	int pos;

    for(i=0; i<COLS; i++)
        for(j=0; j<ROWS; j++)
		{
#ifdef USE_STD_CONFIG
			CellGrid[i][j].LUTVal = configArray[rand() % STD_CONFIG_NUM].Val;
#else
			CellGrid[i][j].LUTVal = 0;
			for(p=0; p<LUT_SIZE; p++)
			{
				CellGrid[i][j].LUTVal <<= 1;
				if(NORM_RAND > 0.5)
					CellGrid[i][j].LUTVal |= 1;
			}
#endif
		}
	mod = 1;
}

void Individuo::arrayInit(int vect[DEF_COLS][DEF_ROWS][LUT_SIZE])
{
	#ifdef USE_STD_CONFIG
		printf("[WARNING] - Configuration may be non-standard\n"); 
	#endif
	int i,j,p;
	for(i=0;i<COLS;i++)
	{
		for(j=0;j<ROWS;j++)
		{
			CellGrid[i][j].LUTVal = 0;
			for(p=0;p<LUT_SIZE;p++)
				{
				if(vect[i][j][p]==1)
					{
					CellGrid[i][j].LUTVal = CellGrid[i][j].LUTVal | (1 << p);
					}
				}
		}
	}
}

void Individuo::toArray(int *** vect)
{
	int i,j,p;
	for(i=0;i<COLS;i++)
	{
		for(j=0;j<ROWS;j++)
		{
			for(p=0;p<LUT_SIZE;p++)
				{
				vect[i][j][p] =0 ;
				if(CellGrid[i][j].LUTVal & (1 << p))
					{
					vect[i][j][p] =1 ;
					}
				}
		}
	}
}

int Individuo::readBit(int i, int j, int p)
{
if(CellGrid[i][j].LUTVal & (1 << p)) return 1;
else return 0;

}




void Individuo::print_geno()
{
    int i,j,p,k;

    for(i=0; i<COLS; i++)
        for(j=0; j<ROWS; j++)
        {
			printf("(%d,%d) = [",i,j);
			for(p=0; p<LUT_SIZE; p++)
			{
				if (CellGrid[i][j].LUTVal & (1 << p))
					printf("1");
				else
					printf("0");
			}
			printf("]");
		#ifdef USE_STD_CONFIG
			for(k=0; k<STD_CONFIG_NUM; k++)
				if (configArray[k].Val == CellGrid[i][j].LUTVal)
				{
					printf(" [%s]",configArray[k].Name);
					break;
				}
			if (k == STD_CONFIG_NUM)
				printf(" [???]");
		#endif

		#ifdef INJECT_ERRORS
			for(k=0; k<ERROR_LIST_DIM; k++)
				if (malfArray[k].X == i && malfArray[k].Y == j)
				{
					printf(" [%08X]",malfArray[k].bitMask);
					break;
				}
		#endif
			printf("\n");
		}
   }

void Individuo::reset_FF()
{
    int i,j;

    for(i=0; i<COLS; i++)
        for(j=0; j<ROWS; j++)
			CellGrid[i][j].FlipFlop = 0;
}

op_type Individuo::compute(op_type* inVals, Cell* actCell,int dbg)
{
	op_type		C;
	HERAuint8	index,oldFF;
	int			i;

	oldFF = index = actCell->FlipFlop;
	for(i=0; i<INPUT_SIGNALS; i++)
	{
		index <<= 1;
		if (inVals[i] == 1)
			index |= 1;
	}

	if (actCell->LUTVal & (1 << (31-index)))
		C = actCell->FlipFlop = 1;
	else
		C = actCell->FlipFlop = 0;

	IF_DBG_VERB_DBG(if (dbg)
	{
		printf("[%d,", oldFF);
		for(i=0; i<INPUT_SIGNALS; i++)
			printf("%u,",inVals[i]);
		printf("] = %d C[31-%d = %d] = %d\n",index,index,31-index,C);
	})
	return C;
}

/*
 *  Implementazione row-by-row
 */
op_type Individuo::simulate_run(op_type *input, int dbg)
{
    op_type   temp_data[2][ROWS];
	int		i,j,curIndex;
	Cell	*actCell;
	HERAuint8	returnVal;

	IF_DBG_VERB_DBG(dbg = 1; print_geno(); printf("Individuo::simulate_run: Input Array: [");)

	for(i=0; i<ROWS; i++)
	{
		temp_data[0][i] = input[i];
		IF_DBG_VERB_DBG(if (i) printf(","); printf("%d",input[i]);)
	}

	IF_DBG_VERB_DBG(printf("]\n");)

	curIndex = 1;
    for(i=0; i<COLS; i++)
	{
        for(j=0; j<ROWS; j++)
        {
			IF_DBG_VERB_DBG(if (dbg) printf("Cella [%d][%d]\n",i,j);)
            actCell = &CellGrid[i][j];
            temp_data[curIndex][ROWS-1-j] = compute( &temp_data[1 - curIndex][(j % 2) ? 0 : INPUT_SIGNALS],actCell,dbg);
        }
		curIndex = 1 - curIndex;
	}

	returnVal = 0;
	//for(i=ROWS-1; i>=0; i--)
	for(i=0; i<ROWS; i++)
	{
		returnVal<<=1;
		if(temp_data[1-curIndex][i])
			returnVal |= 1;
	}

	IF_DBG_VERB_DBG(if (dbg)
	{
		printf("{");
		for(i=0; i<ROWS; i++)
			printf("%d,",temp_data[1-curIndex][i]);

		printf("} ReturnVal: %d\n",returnVal);
	})

	return (op_type)returnVal;
}


int Individuo::create_dxf_rp(char *path)
{
	/*char str[255];
	unsigned char calcolato[COLS*ROWS+1];
	deque<int> op_deque;
    int OP1,OP2,op,actX,actY,actEL;
	int OPX,OPY;
    Cell *actCell;
	DxfWriter dxfw(path);

    dxfw.add_line(0,0,(COLS+1)*DXF_O_GAP+COLS*DXF_LATO_CFB,0);
    dxfw.add_line(0,-((ROWS+1)*DXF_V_GAP+ROWS*DXF_LATO_CFB),(COLS+1)*DXF_O_GAP+COLS*DXF_LATO_CFB,-((ROWS+1)*DXF_V_GAP+(ROWS)*DXF_LATO_CFB));
    dxfw.add_line(0,0,0,-((ROWS+1)*DXF_V_GAP+ROWS*DXF_LATO_CFB));
    dxfw.add_line((COLS+1)*DXF_O_GAP+COLS*DXF_LATO_CFB,0,(COLS+1)*DXF_O_GAP+COLS*DXF_LATO_CFB,-((ROWS+1)*DXF_V_GAP+ROWS*DXF_LATO_CFB));

    memset(calcolato,0,(ROWS*COLS+1)*sizeof(unsigned char));
    //memset(temp_data,0,ROWS*COLS*sizeof(int));

	op_deque.push_front(EL(COLS,0));

    while(!op_deque.empty())
    {
        actEL = op_deque.front();
        op_deque.pop_front();

		actY = ROW(actEL); actX = COL(actEL);
		//printf("[%d,%d]\n",actX,actY);
		if(calcolato[actEL]){continue;}

        if(actX<COLS)
			actCell = &CellGrid[actX][actY];
		else
			actCell = &OutPutCell;

		calcolato[actEL] = 1;

		op = actCell->op;
		op2string(op,str);

		if(actX<COLS)
		{
			dxfw.add_line(DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)),DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)+DXF_LATO_CFB,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)));
			dxfw.add_line(DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)),DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+DXF_LATO_CFB+actY*(DXF_V_GAP+DXF_LATO_CFB)));
			dxfw.add_line(DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+DXF_LATO_CFB+actY*(DXF_V_GAP+DXF_LATO_CFB)),DXF_O_GAP+DXF_LATO_CFB+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+DXF_LATO_CFB+actY*(DXF_V_GAP+DXF_LATO_CFB)));
			dxfw.add_line(DXF_O_GAP+DXF_LATO_CFB+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)),DXF_O_GAP+DXF_LATO_CFB+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+DXF_LATO_CFB+actY*(DXF_V_GAP+DXF_LATO_CFB)));

			dxfw.add_text(DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)+0.33*DXF_LATO_CFB,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+0.5*DXF_LATO_CFB)-1,2,str);
		}
		else
		{
			dxfw.add_line(2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)),2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)+DXF_LATO_CFB,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)));
			dxfw.add_line(2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)),2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+DXF_LATO_CFB+actY*(DXF_V_GAP+DXF_LATO_CFB)));
			dxfw.add_line(2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+DXF_LATO_CFB+actY*(DXF_V_GAP+DXF_LATO_CFB)),2*DXF_O_GAP+DXF_LATO_CFB+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+DXF_LATO_CFB+actY*(DXF_V_GAP+DXF_LATO_CFB)));
			dxfw.add_line(2*DXF_O_GAP+DXF_LATO_CFB+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)),2*DXF_O_GAP+DXF_LATO_CFB+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+DXF_LATO_CFB+actY*(DXF_V_GAP+DXF_LATO_CFB)));

			dxfw.add_text(2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)+0.33*DXF_LATO_CFB,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+0.5*DXF_LATO_CFB)-1,2,str);
		}

		if(n_op(op)>=1)
		{
			if(actCell->input1< N_ING)
			{	//disegnare ingresso immediato input1
				//A = input[actCell->input1];
				sprintf(str,"I%d",actCell->input1);

				if(actX<COLS)
				{
					dxfw.add_line(DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+DXF_LATO_CFB/4.0),DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)-0.83*DXF_O_GAP,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+DXF_LATO_CFB/4.0));
					dxfw.add_text(DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)-0.83*DXF_O_GAP,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+0.9*DXF_LATO_CFB/4.0),2,str);
				}
				else
				{
					dxfw.add_line(2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+DXF_LATO_CFB/4.0),2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)-0.83*DXF_O_GAP,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+DXF_LATO_CFB/4.0));
					dxfw.add_text(2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)-0.83*DXF_O_GAP,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+0.9*DXF_LATO_CFB/4.0),2,str);
				}
			}
			else
			{
				//Disegnare riferimento a cella OP1 da primo ingresso
				OP1 = actCell->input1-N_ING+MAX(0,actX-LB)*ROWS;
				OPX = COL(OP1); OPY = ROW(OP1);

				if(actX<COLS)
					dxfw.add_line(DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+DXF_LATO_CFB/4.0),DXF_O_GAP+OPX*(DXF_O_GAP+DXF_LATO_CFB)+DXF_LATO_CFB,-(DXF_V_GAP+OPY*(DXF_V_GAP+DXF_LATO_CFB)+DXF_LATO_CFB/2.0));
				else
					dxfw.add_line(2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+DXF_LATO_CFB/4.0),DXF_O_GAP+OPX*(DXF_O_GAP+DXF_LATO_CFB)+DXF_LATO_CFB,-(DXF_V_GAP+OPY*(DXF_V_GAP+DXF_LATO_CFB)+DXF_LATO_CFB/2.0));

				if(!calcolato[OP1])
				{
					op_deque.push_front(OP1);
				}
			}
		}

		if(n_op(op)==2)
		{
			if(actCell->input2< N_ING)
			{
				//Disenare ingresso immediato da input 2
				//B = input[actCell->input2];
				sprintf(str,"I%d",actCell->input2);

				if(actX<COLS)
				{
					dxfw.add_line(DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+3*DXF_LATO_CFB/4.0),DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)-0.83*DXF_O_GAP,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+3*DXF_LATO_CFB/4.0));
					dxfw.add_text(DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)-0.83*DXF_O_GAP,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+2.9*DXF_LATO_CFB/4.0),2,str);
				}
				else
				{
					dxfw.add_line(2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+3*DXF_LATO_CFB/4.0),2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)-0.83*DXF_O_GAP,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+3*DXF_LATO_CFB/4.0));
					dxfw.add_text(2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB)-0.83*DXF_O_GAP,-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+2.9*DXF_LATO_CFB/4.0),2,str);
				}
			}
			else
			{
				//Disegnare riferimento a cella OP2 da secondo ingresso
				OP2 = actCell->input2-N_ING+MAX(0,actX-LB)*ROWS;

				OPX = COL(OP2); OPY = ROW(OP2);

				if(actX<COLS)
					dxfw.add_line(DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+3*DXF_LATO_CFB/4.0),DXF_O_GAP+OPX*(DXF_O_GAP+DXF_LATO_CFB)+DXF_LATO_CFB,-(DXF_V_GAP+OPY*(DXF_V_GAP+DXF_LATO_CFB)+DXF_LATO_CFB/2.0));
				else
					dxfw.add_line(2*DXF_O_GAP+actX*(DXF_O_GAP+DXF_LATO_CFB),-(DXF_V_GAP+actY*(DXF_V_GAP+DXF_LATO_CFB)+3*DXF_LATO_CFB/4.0),DXF_O_GAP+OPX*(DXF_O_GAP+DXF_LATO_CFB)+DXF_LATO_CFB,-(DXF_V_GAP+OPY*(DXF_V_GAP+DXF_LATO_CFB)+DXF_LATO_CFB/2.0));

				if(!calcolato[OP2])
				{
					op_deque.push_front(OP2);
				}
			}
		}

	}


	dxfw.close_file();
	*/
    return 0;

}

void Individuo::mutateCell(int x,int y)
{
	int		bitPos;
	HERAuint32	modMask;
	Cell	*actCell;


	actCell = &CellGrid[x][y];

#ifdef USE_STD_CONFIG
	IF_DBG_VERB_DBG(printf("Individuo::mutateCell: Cella:[%d][%d], oldVal[%X]",x,y,actCell->LUTVal);)

	actCell->LUTVal = configArray[rand() % STD_CONFIG_NUM].Val;
#else
	bitPos = rand() % LUT_SIZE;
	IF_DBG_VERB_DBG(printf("Individuo::mutateCell: Cella:[%d][%d], BitPos:[%d]",x,y,bitPos);)
	IF_DBG_VERB_DBG(printf(", oldVal[%X]",actCell->LUTVal);)

	modMask = 1 << bitPos;

	if (actCell->LUTVal & modMask )
	{
		modMask			= ~modMask;
		actCell->LUTVal &= modMask;
	}
	else
	{
		actCell->LUTVal |= modMask;
	}
#endif

	IF_DBG_VERB_DBG(printf(", NewVal[%X]\n",actCell->LUTVal);)

	return;
}

int  Individuo::mutate(int num_mut)
{
	int i,x,y;

	mod = 1;

	for(i=0; i<num_mut; i++)
	{

		x = rand() % COLS;
		y = rand() % ROWS;

		mutateCell(x,y);
	}

	return num_mut;
}

void  Individuo::write_genotipo(int fp, unsigned int write_mod) throw(IndividuoException)
{
	int i,j,dl;

	for(i=0; i< COLS; i++)
	{
		for(j=0; j<ROWS; j++)
		{
			if ((dl = write(fp,&(CellGrid[i][j]),sizeof(struct Cell))) == -1 )
				throw IndividuoException("Individuo::write_genotipo: fwrite",IndividuoException::ERR_TYPE_FIO);
			else
				if(dl!=sizeof(struct Cell))
				{
					printf("Individuo::write_genotipo: fwrite OVERRUN!!\n!");
					getchar();
				}
		}
	}

	if (write(fp,&fitness,sizeof(unsigned int)) == -1 )
			throw IndividuoException("Individuo::write_genotipo: fwrite",IndividuoException::ERR_TYPE_FIO);

	if (write_mod)
		if (write(fp,&mod,sizeof(HERAuint8)) == -1 )
			throw IndividuoException("Individuo::write_genotipo: fwrite",IndividuoException::ERR_TYPE_FIO);

}

void Individuo::read_genotipo(int fp, unsigned int read_mod)  throw(IndividuoException)
{
	int i,j,dl,ndl;
	unsigned char *actCell;

	for(i=0; i<COLS; i++)
	{
		for(j=0; j<ROWS; j++)
		{
			actCell = (unsigned char*)&(CellGrid[i][j]);
			dl = 0;
			do
			{
				if ((ndl=read(fp,actCell,sizeof(Cell)-dl)) == -1 )
					throw IndividuoException("Individuo::read_genotipo: read",IndividuoException::ERR_TYPE_FIO);
				else
					if(ndl!=sizeof(struct Cell)-dl)
					{
						printf("Individuo::read_genotipo: read OVERRUN [%d,%d]\n",ndl,sizeof(struct Cell)-dl);
					}
				dl+=ndl;
				actCell+=ndl;
			} while(dl<sizeof(struct Cell));
		}
	}

	dl = 0;
	actCell = (unsigned char*)&fitness;
	do
	{
		if ((ndl=read(fp,actCell,sizeof(unsigned int)-dl)) == -1 )
			throw IndividuoException("Individuo::read_genotipo: read fitness",IndividuoException::ERR_TYPE_FIO);
		else
			if(ndl!=sizeof(unsigned int)-dl)
			{
				printf("Individuo::read_genotipo: read fitness OVERRUN [%d,%d]\n",ndl,sizeof(unsigned int)-dl);
			}
		dl+=ndl;
		actCell+=ndl;
	} while(dl<sizeof(unsigned int));

	//if (read(fp,&fitness,sizeof(unsigned int)) != sizeof(unsigned int) )
	//	throw IndividuoException("Individuo::read_genotipo: read fitness",IndividuoException::ERR_TYPE_FIO);

	if (read_mod)
	{
		if (read(fp,&mod,sizeof(HERAuint8)) != sizeof(HERAuint8) )
			throw IndividuoException("Individuo::read_genotipo: read mod",IndividuoException::ERR_TYPE_FIO);
	}
	else
		mod = 1;
}

int Individuo::crossover_single_point(const Individuo &g1,const Individuo &g2,Individuo &f1,Individuo &f2)
{
	int cp,xp,yp,e,i,j;

	cp = rand() % (g1.COLS*g1.ROWS);
	//xp = COL(cp); yp = ROW(cp);
	xp = cp / g1.ROWS;
	yp = cp % g1.ROWS;
	//printf("Crossover Point = %d = (%d,%d)\n",cp,xp,yp);
	//getchar();

	i=0; j=0;
	for(e=0; e<=cp; e++)
	{
		f1.CellGrid[i][j] = g1.CellGrid[i][j];
		f2.CellGrid[i][j] = g2.CellGrid[i][j];
		j++;
		if(j==g1.ROWS)
		{
			j=0; i++;
		}
	}

	for(;e<g1.COLS*g1.ROWS;e++)
	{
		f1.CellGrid[i][j] = g2.CellGrid[i][j];
		f2.CellGrid[i][j] = g1.CellGrid[i][j];
		j++;
		if(j==g1.ROWS)
		{
			j=0; i++;
		}
	}

	f1.mod = 1;
	f2.mod = 1;

	return cp;
}

void Individuo::operator= (const Individuo& I)
{
	int i;
	if(I.COLS != COLS || I.ROWS!=ROWS)
	{
		COLS = I.COLS;
		ROWS = I.ROWS;

		IF_DBG_VERB(printf("Individuo::operator=: Resize (%d,%d)\n",ROWS,COLS);)

		CellGrid = (Cell**)realloc(CellGrid,COLS*sizeof(Cell*));
		for(i=0; i<COLS; i++)
		{
			CellGrid[i] = (Cell*)realloc(CellGrid[i],ROWS*sizeof(Cell));
		}

	}

	for(i=0; i<COLS; i++)
		memcpy(CellGrid[i], I.CellGrid[i], sizeof(Cell)*ROWS);


	fitness = I.fitness;
	mod = I.mod;
}

int Individuo::distance(const Individuo &I)
{
	int i,j, dist;
	if (I.COLS != COLS || I.ROWS != ROWS)
	{
		IF_DBG_INFO(printf("[WARN] Individuo::distance: Confronto tra individui di dimensione differente.\n");)
		return -1;
	}

	dist = 0;
	for(i=0; i<COLS; i++)
		for(j=0; j<ROWS; j++)
		#ifdef USE_STD_CONFIG
			if (CellGrid[i][j].LUTVal != I.CellGrid[i][j].LUTVal)
				dist++;
		#else
			dist += utils::hamming_dist((HERAuint8*)&CellGrid[i][j].LUTVal, (HERAuint8*)&I.CellGrid[i][j].LUTVal, 4, 8);
		#endif
	return dist;
}

bool Individuo::equals (const Individuo& I) const
{
	int i,j;
	//bool value=true;
	if (I.COLS != COLS || I.ROWS != ROWS)
	{
		IF_DBG_INFO(printf("[WARN] Individuo::distance: Confronto tra individui di dimensione differente.\n");)
		return -1;
	}
	for(i=0; i<COLS; i++)
		for(j=0; j<ROWS; j++)
			{//printf("%d %d\n", CellGrid[i][j].LUTVal, I.CellGrid[i][j].LUTVal);
			if(CellGrid[i][j].LUTVal != I.CellGrid[i][j].LUTVal) 
			{
			return false;}
			}
	return true;
}

int Individuo::getOffspring(Individuo * father, Individuo * s1, Individuo * s2)
{
if(s1==NULL || s2==NULL)
	{
	printf("[ERROR] NULL pointer to element\n");
	exit(1);
	}
if(equals(*father))
	{
	s1=father;
	s2=father;
	return 0;
	}
else
	{
	int i,j,k;
	float m=1;
	float f=1;
	float r=0,t=0;
	for(i=0;i<COLS;i++)
		{
		for(j=0;j<ROWS;j++)
			{
			s1->CellGrid[i][j].LUTVal=0;
			s2->CellGrid[i][j].LUTVal=0;
			for(k=0;k<4;k++)
				{
				r=NORM_RAND;
				t=(float)(m/(m+f));
				if(r > t)
					{
					//GET FROM M-mother (this)
					m++;
					//printf("X: %d\n", s1->CellGrid[i][j].LUTVal | (CellGrid[i][j].LUTVal & (0x000000FF << (8*k))));
					s1->CellGrid[i][j].LUTVal =( s1->CellGrid[i][j].LUTVal | (CellGrid[i][j].LUTVal & (0x000000FF << (8*k))));
					//printf("X2: %d\n", s1->CellGrid[i][j].LUTVal | (CellGrid[i][j].LUTVal & (0x000000FF << (8*k))));

					//get from father
					s2->CellGrid[i][j].LUTVal =( s2->CellGrid[i][j].LUTVal | (father->CellGrid[i][j].LUTVal & (0x000000FF << (8*k))));
					//printf("+");
					}
				else
					{
					//GET FROM F-father
					f++;
					s1->CellGrid[i][j].LUTVal =( s1->CellGrid[i][j].LUTVal | (father->CellGrid[i][j].LUTVal & (0x000000FF << (8*k))));
					//get from mother
					s2->CellGrid[i][j].LUTVal =( s2->CellGrid[i][j].LUTVal | (CellGrid[i][j].LUTVal & (0x000000FF << (8*k))));
					//printf("-");
					}
				
				}
			
			//printf("F: %d\n", father->CellGrid[i][j].LUTVal);
			//printf("M: %d\n", this->CellGrid[i][j].LUTVal);
			//printf("EL: %d %d\n", s1->CellGrid[i][j].LUTVal,s2->CellGrid[i][j].LUTVal);
			}
		}
	//s1->print_geno();
	return 1;
	}
}



#ifdef INJECT_ERRORS
void Individuo::injectAllErrors()
{
	int i;
	HERAuint32 errorMask;

	for(i=0; i<ERROR_LIST_DIM; i++)
	{

		CellGrid[malfArray[i].X][malfArray[i].Y].LUTVal &= !malfArray[i].bitMask;
		errorMask = rand() % 0xFFFFFFFF;
		errorMask &= malfArray[i].bitMask;
		IF_DBG_VERB_DBG(printf("Individuo::injectAllErrors: @[%d][%d]: [%08X]\n",malfArray[i].X,malfArray[i].Y,errorMask);)
		CellGrid[malfArray[i].X][malfArray[i].Y].LUTVal |= errorMask;
	}
}
#endif
